﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;


namespace HH
{
    public class Class1
    {
        #region 成员变量
        public string path = "D:\\";  //面积标注块所在路径
        public Database db = HostApplicationServices.WorkingDatabase;  //工作空间数据库
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; //获取当前活动文档的Editor对象，也就是命令行           
        Document doc = Application.DocumentManager.MdiActiveDocument; //当前活动文档
        List<Polyline> plines = new List<Polyline>(); //可标记的图形集合
        string BLName = "BL";
        #endregion
        #region 测试方法
        [CommandMethod("SayHello")]
        public void SayHello()
        {
            //获取当前活动文档的Editor对象，也就是命令行
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            //调用Editor对象的WriteMessage函数在命令行上显示文本
            ed.WriteMessage("欢迎进入.NET开发AutoCAD的世界！");
        }
        #endregion
        #region 成员方法
        /// <summary>
        /// 标记面积
        /// </summary>
        [CommandMethod("MarkArea")]
        public void MarkArea()
        {
            ed.WriteMessage("面积标注程序开始........");

            using (DocumentLock dl = doc.LockDocument())
            {
                //打开图层表
               // LayerTable layerTable = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForWrite);
                //用户指定一个图层
                PromptStringOptions optionStr = new PromptStringOptions("请输入需要标注的图层名:");
                string layer = "0";   
                //确保用户输入正确的图层名
              //  bool repeat = true;
             //   while (repeat)
               // {
                    PromptResult result = ed.GetString(optionStr);
                    layer = result.StringResult;
                //    repeat = false;
                 //   if (!layerTable.Has(layer))
                  //  {
                   //     ed.WriteMessage("您输入的图层不存在!请重新输入：");
                    //    repeat = true;
                   // }
                //}
                
              //  ed.WriteMessage("您选择的图层为:" + layer);

                //选择集过滤器
                TypedValue[] values = new TypedValue[]
                {
                    new TypedValue((int)DxfCode.LayerName,layer),
                    new TypedValue((int)DxfCode.Start,"*PolyLine")
                };
                SelectionFilter filter = new SelectionFilter(values);
                //选择结果
                PromptSelectionResult selres = ed.SelectAll(filter);
                //筛选可用的封闭的多段线
                if (selres.Status == PromptStatus.OK)
                {
                    using (Transaction trans = doc.TransactionManager.StartTransaction())
                    {
                        ObjectId[] ids = selres.Value.GetObjectIds();
                        foreach (ObjectId id in ids)
                        {
                            Polyline pl = (Polyline)trans.GetObject(id, OpenMode.ForRead);
                            if (pl.Closed)
                            {
                                plines.Add(pl);
                            }
                        }
                    }
                }
                else
                {
                    ed.WriteMessage("获取多段线失败！");
                }
                ed.WriteMessage("获取多边形完毕！");
                //获取标注快
                GetBlock();
                //对筛选出来的多段线操作
                foreach (Polyline pl in plines) //遍历所有封闭图形
                {
                    //对每一个多边形操作
                    ed.WriteMessage(pl.Id.ToString() + ":" + pl.Area.ToString());
                    double Area = pl.Area; //多段线围成封闭图形的面积
                    double per = pl.Length;//图形周长
                    Point3d centure = GetCenture(pl); //图形中心
                    Dictionary<string, string> attributes = new Dictionary<string, string>(); //属性值
                    attributes.Add("AREA", Area.ToString());
                    attributes.Add("PER", per.ToString());
                    //当前模型空间ID
                    ObjectId spaceID = db.CurrentSpaceId;
                    double[] attr = new double[] { Area, per };


                    InsertBlockReference(spaceID, layer, BLName, centure, new Scale3d(1), 0d, attributes, attr);

                   // ed.WriteMessage("面积：" + Area.ToString());
                   // ed.WriteMessage("周长：" + per.ToString());
                   // ed.WriteMessage("标注位置："+centure.ToString());
                    

                }
            }


        }
        /// <summary>
        /// 获取图形中心
        /// </summary>
        /// <param name="pl">多段线</param>
        /// <returns>中心点坐标</returns>
        public Point3d GetCenture(Polyline pl)
        {
            //此算法尚未确定，暂时返回临时坐标坐标作为后续开发前提。
            Point2d p1 = pl.GetPoint2dAt(0);
            Point2d p2 = pl.GetPoint2dAt(1);
            Point2d p3 = pl.GetPoint2dAt(2);
            Vector2d v1 = new Vector2d(p2.X-p3.X, p2.Y-p3.Y);
            double Lp1 = v1.Length;

            Vector2d v2 = new Vector2d(p1.X - p3.X, p1.Y - p3.Y);
            double Lp2 = v2.Length;

            Vector2d v3 = new Vector2d(p1.X - p2.X, p1.Y - p2.Y);
            double Lp3 = v3.Length;

            double x = (Lp1 * p1.X + Lp2 * p2.X + Lp3 * p3.X) / (Lp1 + Lp2 + Lp3);
            double y = (Lp1 * p1.Y + Lp2 * p2.Y + Lp3 * p3.Y) / (Lp1 + Lp2 + Lp3);

            return new Point3d(x, y, 0);
        }
        /// <summary>
        /// 插入标注块
        /// </summary>
        public void GetBlock()
        {
            //创建一个新的数据库对象，作为源数据库，以读取外部文件中的对象
            Database sourceDB = new Database(false, true);
            string sourcePath = path + "BL.dwg";
            try //错误处理
            {
                //把DWG文件读入到一个临时的数据库中，即读取标注块（BL.DWG）
                sourceDB.ReadDwgFile(sourcePath, FileShare.Read, true, null);
                //创建一个变量用来存储块的ObjectID列表
                ObjectIdCollection blockIDs = new ObjectIdCollection();
                //获取源数据库的事务处理管理器
                Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDB.TransactionManager;
                //在源数据库中开始事务处理
                using (Transaction myT = tm.StartTransaction())
                {
                    //打开源数据库中的块表
                    BlockTable bt = (BlockTable)tm.GetObject(sourceDB.BlockTableId, OpenMode.ForRead, false);
                    ed.WriteMessage("test");
                    //遍历每个块
                    foreach (ObjectId btrid in bt)
                    {
                        BlockTableRecord btr = (BlockTableRecord)tm.GetObject(btrid, OpenMode.ForRead, false);
                        //只加入命名块和非布局块到复制列表中
                        if (!btr.IsAnonymous && !btr.IsLayout)
                        {
                            blockIDs.Add(btrid);
                        }
                        btr.Dispose();
                    }
                    bt.Dispose();
                }
                //定义一个IDMapping对象
                IdMapping mapping = new IdMapping();
                //从源数据库向目标数据库复制块表记录
                sourceDB.WblockCloneObjects(blockIDs, db.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
            }
            //出错处理
            catch (Autodesk.AutoCAD.Runtime.Exception ex)
            {
                Application.ShowAlertDialog("复制错误：" + ex.Message);
            }
        }
        /// <summary>
        /// 插入块参照
        /// </summary>
        /// <param name="spaceID">模型空间ID</param>
        /// <param name="layer">图层</param>
        /// <param name="blockName">块名</param>
        /// <param name="position">插入位置</param>
        /// <param name="scale">缩放比例</param>
        /// <param name="rotateAngle">旋转角度</param>
        /// <param name="attNameValue">属性值</param>
        /// <returns></returns>
        public ObjectId InsertBlockReference(ObjectId spaceID,string layer,string blockName,Point3d position,Scale3d scale,double rotateAngle,Dictionary<string,string> attNameValue,double[] attr)
        {
            #region 命令行版本

           // string cmd = string.Format("_insert {0} {1},{2}   {3} {4}", "D:\\BL.DWG", position.X, position.Y, 123d, 456d);
            string cmd =string.Format( "(command \"_insert\" \"D:\\BL.DWG\" \"{0},{1}\" \"\" \"\" \"{2}\" \"{3}\")\n",position.X,position.Y, Math.Round(attr[0], 2), Math.Round(attr[1], 2));
            doc.SendStringToExecute(cmd, true, false, false);

            return ObjectId.Null;
            #endregion



            #region  c#版本
          /*
            //打开表块
            Database db = spaceID.Database;
            BlockTable bt = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead);
            //检查是否有块
            if (!bt.Has(blockName))
            {
                ed.WriteMessage("标注块添加无效");
                return ObjectId.Null;
            }
            //以写的方式打开模型空间
            BlockTableRecord space = (BlockTableRecord)spaceID.GetObject(OpenMode.ForRead);
            ObjectId btrID = bt[blockName];//获取表块记录的id
            //打开表块记录
            BlockTableRecord record = (BlockTableRecord)btrID.GetObject(OpenMode.ForRead);
            //创建一个块表参照块并设置插入点
            BlockReference br = new BlockReference(position, bt[blockName]);
            br.ScaleFactors = scale;
            br.Layer = layer;
            br.Rotation = rotateAngle;
            space.AppendEntity(br);
            if (record.HasAttributeDefinitions)
            {
                foreach(ObjectId id in record)
                {
                    AttributeDefinition attDef = id.GetObject(OpenMode.ForRead) as AttributeDefinition;
                    if(attDef != null)
                    {
                        //创建新属性
                        AttributeReference attribute = new AttributeReference();
                        attribute.SetAttributeFromBlock(attDef, br.BlockTransform);
                        attribute.Position = attDef.Position.TransformBy(br.BlockTransform);
                        attribute.Rotation = attDef.Rotation;
                        attribute.AdjustAlignment(db);
                        ed.WriteMessage(attDef.Tag.ToUpper());
                        if (attNameValue.ContainsKey(attDef.Tag.ToUpper()))
                        {
                            attribute.TextString = attNameValue[attDef.Tag.ToUpper()].ToString();

                        }
                        br.AttributeCollection.AppendAttribute(attribute);
                        db.TransactionManager.AddNewlyCreatedDBObject(attribute, true);
                    }
                }
            }
            db.TransactionManager.AddNewlyCreatedDBObject(br, true);
            return br.ObjectId;
            */
            #endregion
        }
        #endregion       
    }
}
